package grape.common.service.common;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.interfaces.Func;
import com.baomidou.mybatisplus.core.conditions.interfaces.Join;
import com.baomidou.mybatisplus.core.conditions.interfaces.Nested;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import grape.common.service.po.IDBasePo;
import grape.common.service.query.*;
import grape.common.tools.StringTool;
import grape.common.tools.ToolService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

/**
 * 全局service实现类的基类
 * Created by yangwei
 * Created at 2019/7/23 14:32
 */
@Slf4j
public class BaseServiceImpl<Mapper extends IBaseMapper<Po>,Po extends IDBasePo<String,Po>> extends ServiceImpl<Mapper,Po> implements IBaseService<Po> , ToolService {
    @Override
    public Po insert(Po entity) {
        boolean r = super.save(entity);
        if (r) {
            return entity;
        }

        return null;
    }

    @Override
    public void innerAnnotationSupportWrapper(Wrapper<Po> queryWrapper,BasePoQuery<Po> query){

        if (!BasePoQuery.class.isAssignableFrom(query.getClass())) {
            return;
        }
        // 补充一个条件，否则在拼接or的时候会拼接不对，而是and
        ((AbstractWrapper) queryWrapper).apply(true, "true");
        Po poQuery = query.getPoQuery();
        for (Field field : ReflectUtil.getFields(query.getClass())) {
            Object fieldValue = ReflectUtil.getFieldValue(query, field);
            // orderby处理
            OrderBy orderBy = AnnotationUtil.getAnnotation(field, OrderBy.class);
            if (orderBy != null) {
                String columnName = StringTool.humpToLine(orderBy.value());
                if (isStrEmpty(columnName)) {
                    columnName = StringTool.humpToLine(field.getName());
                }
                ((AbstractWrapper) queryWrapper).orderBy(true, orderBy.asc(), columnName);
            }

            In in = AnnotationUtil.getAnnotation(field, In.class);
            if (in != null && fieldValue != null) {
                Object finalFieldValue = fieldValue;

                (((AbstractWrapper) queryWrapper)).in(StringTool.humpToLine(field.getName()), ((Collection) finalFieldValue));

                setObjectValueNull(poQuery, field.getName());
                continue;
            }

            /*******下面是其它注解处理*********/
            if (fieldValue == null && poQuery != null) {
                fieldValue = ReflectUtil.getFieldValue(poQuery, field.getName());
            }


            if (fieldValue == null) {
                continue;
            }
            // like 处理
            Like like = AnnotationUtil.getAnnotation(field, Like.class);
            if(like != null){
                ((AbstractWrapper) queryWrapper).like( StringTool.humpToLine(field.getName()), fieldValue);

                setObjectValueNull(poQuery, field.getName());
                continue;
            }
            // 大于 处理
            Gt gt = AnnotationUtil.getAnnotation(field, Gt.class);
            if (gt != null) {
                String gtValue = gt.value();
                if (isStrEmpty(gtValue)) {
                    throw new RuntimeException("你必须指定比较字段的名称");
                }
                if (gt.eq()) {
                    ((AbstractWrapper) queryWrapper).ge( StringTool.humpToLine(gtValue), fieldValue);

                }else {
                    ((AbstractWrapper) queryWrapper).gt( StringTool.humpToLine(gtValue), fieldValue);
                }

                continue;
            }
            // 小于 处理
            Lt lt = AnnotationUtil.getAnnotation(field, Lt.class);
            if (lt != null) {
                String ltValue = lt.value();
                if (isStrEmpty(ltValue)) {
                    throw new RuntimeException("你必须指定比较字段的名称");
                }
                if (lt.eq()) {
                    ((AbstractWrapper) queryWrapper).le( StringTool.humpToLine(ltValue), fieldValue);

                }else {
                    ((AbstractWrapper) queryWrapper).lt( StringTool.humpToLine(ltValue), fieldValue);
                }
                continue;
            }
            IsPublic isPublic = AnnotationUtil.getAnnotation(field, IsPublic.class);
            if (isPublic != null) {
                Object orginFieldValue = ReflectUtil.getFieldValue(poQuery,field.getName());
                if (orginFieldValue == null && fieldValue instanceof Boolean && ((Boolean) fieldValue) == true) {
                    Object finalFieldValue = fieldValue;
                    ((AbstractWrapper) ((AbstractWrapper) queryWrapper).or()).eq(StringTool.humpToLine(field.getName()), finalFieldValue);
                }
                continue;
            }
            Or or = AnnotationUtil.getAnnotation(field, Or.class);
            if (or != null) {
                Object finalFieldValue = fieldValue;
                ((AbstractWrapper) ((AbstractWrapper) queryWrapper).or()).eq(StringTool.humpToLine(field.getName()), finalFieldValue);
                setObjectValueNull(poQuery, field.getName());
                continue;
            }

        }// end for

    }

    private void setObjectValueNull(Object obj,String fieldName){
        if (obj != null) {
            try {
                ReflectUtil.setFieldValue(obj,fieldName,null);
            }catch (Exception e){
                log.warn("你利用了查询参数注解，在将原始值设置为空时出错了，但这也许不影响运行的正确性");
            }
        }
    }
    @Cacheable(cacheNames = {"getById"},key = "#id")
    @Override
    public Po getById(Serializable id) {
        if (id == null) {
            return null;
        }
        return super.getById(id);
    }

    @CacheEvict(value="getById",key = "#entity.id")
    @Override
    public boolean updateById(Po entity) {
        return super.updateById(entity);
    }
    @CacheEvict(value="getById",key = "#entity.id")
    @Override
    public boolean updateFullById(Po entity) {
        return retBool(baseMapper.updateFullById(entity));
    }

    @Override
    public boolean updateFull(Po entity, Wrapper<Po> updateWrapper) {
        return retBool(baseMapper.updateFull(entity,updateWrapper));
    }

    @CacheEvict(value="getById",key = "#id")
    @Override
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

}
